package com.xneure.code.bean;

import java.util.LinkedList;
import java.util.Map;
import java.util.Map.Entry;
import com.xneure.code.intf.DiffListen;
import com.xneure.utils.ObjectUtil;
import com.xneure.utils.bean.ClassInfo;

public class DiffCompare{
	private LinkedList<String> paths = new LinkedList<>();
	private DiffListen listen;
	private boolean ignoreCase;

	public boolean isIgnoreCase(){
		return ignoreCase;
	}

	public void setIgnoreCase(boolean ignoreCase){
		this.ignoreCase = ignoreCase;
	}

	public void setListen(DiffListen listen){
		this.listen = listen;
	}

	public void compare(Object src,Object target){
		listen.currObject(src,target);
		if(src == null || target == null){
			listen.Handle(paths,src,target);
			return;
		}
		if(src.getClass().equals(target.getClass()) == false){
			throw new RuntimeException("对象类型不匹配。");
		}
		ClassInfo ci = new ClassInfo(src);
		Map<String,Object> srcValue = ci.getFieldValues();
		ci.setObject(target);
		Map<String,Object> tagValue = ci.getFieldValues();
		Object tv;
		Object sv;
		for(Entry<String,Object> ent:srcValue.entrySet()){
			paths.addLast(ent.getKey());
			if(listen.isIgnore(paths) == false){
				tv = tagValue.get(ent.getKey());
				sv = ent.getValue();
				if(null == tv){
					if(null != sv){
						if(ObjectUtil.isBasicType(sv) || sv instanceof CharSequence){
							listen.Handle(paths,sv,tv);
						}else{
							compare(sv,tv);
						}
					}
				}else{
					if(null == sv){
						listen.Handle(paths,sv,tv);
					}else if(ObjectUtil.isBasicType(sv)){
						if(tv.equals(sv) == false){
							listen.Handle(paths,sv,tv);
						}
					}else if(sv instanceof CharSequence){
						if(ignoreCase){
							if(tv.toString().equalsIgnoreCase(sv.toString()) == false){
								listen.Handle(paths,sv,tv);
							}
						}else{
							if(tv.equals(sv) == false){
								listen.Handle(paths,sv,tv);
							}
						}
					}else{
						if(sv.getClass().isArray()){
							compareArray((Object[])sv,(Object[])tv);
						}else{
							compare(sv,tv);
						}
					}
				}
			}
			paths.removeLast();
			if(listen.isEnd()){
				return;
			}
		}
	}

	public void compareArray(Object[] src,Object[] target){
		Object[] tmp = (Object[])src;
		Object[] tmp1 = (Object[])target;
		int l1 = tmp.length;
		int l2 = tmp1.length;
		int length = Math.max(l1,l2);
		Object t1, t2;
		for(int i = 0;i < length;i++){
			t1 = t2 = null;
			if(i <= l1){
				t1 = tmp[i];
			}
			if(i <= l2){
				t2 = tmp1[i];
			}
			compare(t1,t2);
			if(listen.isEnd()){
				return;
			}
		}
	}
}
